﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using IMLibrary.IO;
using IMLibrary.Net.Enum;

namespace Ourmsg.FileTransmit
{
    /// <summary>
    /// 
    /// </summary>
    public partial class FileTransmitV1 : UserControl
    {
        #region 构造
        /// <summary>
        /// 构造发送端
        /// </summary> 
        public FileTransmitV1(string fullFileName, string MD5, string offlineFileServerIP, string p2pServerIP, int offlineFileServerPort, int p2pServerPort)
        {
            InitializeComponent();
            isSend = true;
            OfflineFileServerIP = offlineFileServerIP;
            OfflineFileServerPort = offlineFileServerPort;
            P2PServerIP = p2pServerIP;
            P2PServerPort = p2pServerPort;
            FullFileName = fullFileName;
            FileInfo f = new FileInfo(fullFileName); 
            if (f.Exists)
            {
                TFileInfo.fullName = FullFileName;
                TFileInfo.Extension = f.Extension;
                TFileInfo.Length = f.Length;
                TFileInfo.Name = f.Name;
                TFileInfo.MD5 = MD5;
                TFileInfo.IsSend = true;
                this.icon = FileIcon.GetFileIcon(FullFileName).ToBitmap();
                labelFileName.Text = TFileInfo.Name;
                labelFileLengthString.Text = Calculate.GetSizeStr(TFileInfo.Length);

                if (P2PFileTransmit == null)
                {
                    P2PFileTransmit = new P2PFileTransmitBaseV1(TFileInfo, P2PServerIP, P2PServerPort,true);
                    setEvent(P2PFileTransmit);
                }
            }
            Initializer();
        }


        /// <summary>
        /// 构造接收端
        /// </summary> 
        public FileTransmitV1(TFileInfo tfileInfo, string p2pServerIP, int p2pServerPort, bool isP2P)//
        {
            InitializeComponent();
            tfileInfo.IsSend = false;
            isSend = false;
            P2PServerIP = p2pServerIP;
            P2PServerPort = p2pServerPort;
            TFileInfo = tfileInfo;
            this.icon = FileIcon.GetFileIcon(TFileInfo.Extension).ToBitmap();
            labelFileName.Text = TFileInfo.Name;
            labelFileLengthString.Text = Calculate.GetSizeStr(TFileInfo.Length);

            if (P2PFileTransmit == null)
            {
                P2PFileTransmit = new P2PFileTransmitBaseV1(TFileInfo, P2PServerIP, P2PServerPort, false);
                setEvent(P2PFileTransmit);
            }

            if (!isSend)
            {
                string CacheFile = "FileCache\\" + TFileInfo.MD5;
                if (File.Exists(CacheFile))//如果缓存文件存在，则触发可断点续传事件
                {
                    this.linkLabelReceive.Visible = false;
                    this.linkLabelResume.Visible = true;
                } 
            }
            Initializer();
        }

        /// <summary>
        /// 构造接收端
        /// </summary> 
        public FileTransmitV1(TFileInfo tfileInfo, string offlineFileServerIP,  int offlineFileServerPort)
        {
            InitializeComponent();
            tfileInfo.IsSend = false; 
            isSend = false;
            OfflineFileServerIP = offlineFileServerIP;
            OfflineFileServerPort = offlineFileServerPort; 
            TFileInfo = tfileInfo; 
            this.icon = FileIcon.GetFileIcon(TFileInfo.Extension).ToBitmap();
            labelFileName.Text = TFileInfo.Name;
            labelFileLengthString.Text = Calculate.GetSizeStr(TFileInfo.Length);
            TcpOfflineFileClient = new OfflineFileClientV1(TFileInfo, OfflineFileServerIP, OfflineFileServerPort, false);
            setEvent(TcpOfflineFileClient, true);
            isOfflineFileTransmit = true;
            if (!isSend)
            {
                string CacheFile = "FileCache\\" +TFileInfo.MD5;
                if (File.Exists(CacheFile))//如果缓存文件存在，则触发可断点续传事件
                    File.Delete(CacheFile);

                this.linkLabelNext.Visible = true;
            }
            Initializer();
        }

        private void Initializer()
        {
            linkLabelCancel.Click += linkLabelCancel_Click;
            linkLabelReceive.Click += linkLabelReceive_Click;
            linkLabelResume.Click += linkLabelResume_Click;
            linkLabelSaveAs.Click += linkLabelSaveAs_Click;
            linkLabelOffline.Click += linkLabelOffline_Click;
            linkLabelNext.Click += linkLabelNext_Click;
        }
        #endregion

        #region 属性

        string OfflineFileServerIP = "127.0.0.1";
        int OfflineFileServerPort;
        string P2PServerIP = "127.0.0.1";
        int P2PServerPort;
        string FullFileName = "";

        public TFileInfo TFileInfo = new TFileInfo();

        /// <summary>
        /// 标识文件传输是离线传输还是P2P实时传输（true为离线文件传输，false为P2P）
        /// </summary>
        private bool isOfflineFileTransmit = false;


        #region P2P文件
        private  P2PFileTransmitBaseV1 P2PFileTransmit = null;

        private OfflineFileClientV1 TcpOfflineFileClient = null;

        #endregion

        #region 属性

        bool _isSend = false;
        /// <summary>
        /// 发送方
        /// </summary>
        private bool isSend
        {
            set
            {
                _isSend = value;
                if (value)
                {
                    this.labelRequest.Text = "发送文件请求：";
                    this.linkLabelReceive.Visible = false;
                    this.linkLabelSaveAs.Visible = false;
                    this.linkLabelOffline.Visible = true;
                }
                else
                {
                    this.labelRequest.Text = "接收文件请求：";
                }
            }
            get { return _isSend; }
        }

        private Image icon
        {
            set
            {
                if (value != null)
                    pictureBox1.Image = value;
            }
            get { return pictureBox1.Image; }
        }
        #endregion

        #endregion

        #region 设置事件
        /// <summary>
        /// 设置事件
        /// </summary>
        /// <param name="value"></param>
        private void setEvent(P2PFileTransmitBaseV1 value)
        {
            value.Connected += (s, e) => showInfo(TransmitState.Connected, TFileInfo);
            value.Transmitting += (s, e) => showInfo(TransmitState.Transmitting, e.fileInfo);
            value.Transmitted += (s, e) =>
                {
                    if (Transmitted != null)
                        Transmitted(this, e);//触发文件 
                };
            value.AllowResume += (s, e) =>
            {
                if (!isOfflineFileTransmit)//如果不是离线文件
                {
                    this.linkLabelReceive.Visible = false;
                    this.linkLabelResume.Visible = true;
                }
            };
            value.ServerRegistered += (s, e) =>
                {
                    OnServerRegistered(new fileTransmitEvnetArgs(e.ServerID));
                };
        }

        private void setEvent(OfflineFileClientV1 value, bool isReceive = false)
        {
            value.Connected += (s, e) => showInfo(TransmitState.Connected, TFileInfo);
            value.Transmitting += (s, e) => showInfo(TransmitState.Transmitting, e.fileInfo);
            value.Transmitted += (s, e) =>
            {
                if (!isReceive)
                    OnOfflineFileTransmited();

                if (Transmitted != null)
                    Transmitted(this, e);//触发文件传输结束事件 
            };
        }
        #endregion

        #region 离线文件单击事件
        private void linkLabelOffline_Click(object sender, EventArgs e)
        {
            if (P2PFileTransmit != null)
            {
                P2PFileTransmit.CancelTransmit();
                P2PFileTransmit = null;
            }
            if (TcpOfflineFileClient == null)
            {
                TcpOfflineFileClient = new OfflineFileClientV1(TFileInfo, OfflineFileServerIP, OfflineFileServerPort, true);
                setEvent(TcpOfflineFileClient);
                TcpOfflineFileClient.Start();//开始传输文件
            }
             
            linkLabelOffline.Visible = false;
            OnOfflineFile();//触发离线文件传输事件
        }
        #endregion

        #region 离线文件下次接收 单击事件
        void linkLabelNext_Click(object sender, EventArgs e)
        {
            if (NextReceive != null)
                NextReceive(this, null);
        }
        #endregion

        #region 文件传输事件
        public delegate void fileTransmitEventHandler(object sender, fileTransmitEvnetArgs e);
        /// <summary>
        /// 取消文件传输
        /// </summary>
        public event fileTransmitEventHandler TransmitCancel;
        /// <summary>
        /// 文件传输结束
        /// </summary>
        public event fileTransmitEventHandler Transmitted;
    
        /// <summary>
        /// 离线文件下次接收事件
        /// </summary>
        public event fileTransmitEventHandler NextReceive;
        /// <summary>
        /// 文件正被其他人传输...
        /// </summary>
        public event fileTransmitEventHandler ElseTransmiting;
        /// <summary>
        /// 注册服务成功事件
        /// </summary>
        public event fileTransmitEventHandler ServerRegistered;
        private void OnServerRegistered(fileTransmitEvnetArgs e)
        {
            if (ServerRegistered != null)
                ServerRegistered(this, e);
        }

        /// <summary>
        /// 离线文件传输事件
        /// </summary>
        public event fileTransmitEventHandler OfflineFile;
        /// <summary>
        /// 触发离线文件传输事件
        /// </summary>
        public void OnOfflineFile()
        {
            if (OfflineFile != null)
                OfflineFile(this, new fileTransmitEvnetArgs(TFileInfo));
        }


        /// <summary>
        /// 离线文件传输事件
        /// </summary>
        public event fileTransmitEventHandler  OfflineFileTransmited;
        /// <summary>
        /// 触发离线文件传输结束事件
        /// </summary>
        public void OnOfflineFileTransmited()
        {
            if (OfflineFileTransmited != null)
                OfflineFileTransmited(this, new fileTransmitEvnetArgs(TFileInfo));
        }

        /// <summary>
        /// 文件传输状态
        /// </summary>
        private enum TransmitState
        {
            Connected,
            Transmitted,
            OutTime,
            Transmitting,
            Over,
            Else,
            Error,
            Before,
        }

        private void showInfo(TransmitState State, TFileInfo fileInfo)
        {
            try
            {
                delegateSetRecControl d = new delegateSetRecControl(SetRecControl);
                this.Invoke(d, State, fileInfo);
            }
            catch { }
        }

        delegate void delegateSetRecControl(TransmitState State, TFileInfo fileinfo);
        private void SetRecControl(TransmitState State, TFileInfo fileinfo)
        {
            if (State == TransmitState.Transmitting)
            { 
                if (fileinfo.CurrLength > fileinfo.Length) return;
                this.progressBar1.Value = Convert.ToInt32(((decimal)fileinfo.CurrLength / fileinfo.Length) * 100);
                this.labelFileLengthString.Text = Calculate.GetSizeStr(fileinfo.CurrLength) + "/" +Calculate.GetSizeStr(fileinfo.Length);
            }
            else if (State == TransmitState.Connected)
            {
                linkLabelOffline.Visible = false;

                if (isSend)
                    this.labelRequest.Text = "正在发送...";
                else
                    this.labelRequest.Text = "正在接收..."; 

                if (this.P2PFileTransmit != null)
                {
                    if (this.P2PFileTransmit.ConnectionType == ConnectionType.UDPTurn)
                        labelConType.Text = "[UDP中转]";
                    else
                        labelConType.Text = "[UDP直连]";
                }
                else
                    labelConType.Text = "[服务器中转]";
            } 
            else if (State == TransmitState.Before)
            {
                linkLabelOffline.Visible = false;
            }
            else if (State == TransmitState.Else)
            {
                MessageBox.Show("其他用户正在上传同一文件，请稍后再试！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                if (ElseTransmiting != null)
                    ElseTransmiting(this, null);
            }
        }
        #endregion

        #region 接收文件单击事件
        void linkLabelSaveAs_Click(object sender, EventArgs e)
        {
            SaveFileDialog sf = new SaveFileDialog();
            sf.FileName = TFileInfo.Name;
            sf.Filter = "*" + TFileInfo.Extension + "|";
            if (sf.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (!isOfflineFileTransmit)
                {
                    if (sf.FileName.IndexOf(TFileInfo.Extension, 0) < 0)
                        P2PFileTransmit.TFileInfo.fullName = sf.FileName + TFileInfo.Extension;
                    else
                        P2PFileTransmit.TFileInfo.fullName = sf.FileName;

                    P2PFileTransmit.StartFileTransmit(true);//接收文件，并执行断点续传
                }
                else
                {
                    if (sf.FileName.IndexOf(TFileInfo.Extension, 0) < 0)
                        TcpOfflineFileClient.TFileInfo.fullName = sf.FileName + TFileInfo.Extension;
                    else
                        TcpOfflineFileClient.TFileInfo.fullName = sf.FileName;
                    TcpOfflineFileClient.Start();
                }

                linkLabelSaveAs.Visible = false;
                linkLabelReceive.Visible = false;
                linkLabelResume.Visible = false;
                linkLabelNext.Visible = false;
            }

        }

        void linkLabelReceive_Click(object sender, EventArgs e)
        {
            linkLabelSaveAs.Visible = false;
            linkLabelReceive.Visible = false;
            linkLabelNext.Visible = false;
            linkLabelResume.Visible = false;

            if (!isOfflineFileTransmit)
            { 
                P2PFileTransmit.TFileInfo.fullName = "ReceivedFile\\" + TFileInfo.Name;
                P2PFileTransmit.StartFileTransmit(false);//接收文件，不执行断点续传 
            }
            else
            {
                TcpOfflineFileClient.TFileInfo.fullName = "ReceivedFile\\" + TFileInfo.Name;
                TcpOfflineFileClient.Start();
            }
        }
        #endregion

        #region 取消文件传输
        void linkLabelCancel_Click(object sender, EventArgs e)
        {
            linkLabelCancel.Enabled = false;
            CancelTransmit();
            if (TransmitCancel != null)
                TransmitCancel(this, new fileTransmitEvnetArgs(TFileInfo));
        }
        #endregion

        #region 续传单击事件
        private void linkLabelResume_Click(object sender, EventArgs e)
        {
            linkLabelSaveAs.Visible = false;
            linkLabelReceive.Visible = false;
            linkLabelResume.Visible = false;
             
            P2PFileTransmit.TFileInfo.fullName = "ReceivedFile\\" + P2PFileTransmit.TFileInfo.Name;
            P2PFileTransmit.StartFileTransmit(true);//接收文件，执行断点续传 
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 取消文件传输
        /// </summary>
        public void CancelTransmit()
        {
            if (P2PFileTransmit != null)
                P2PFileTransmit.CancelTransmit();//取消文件传输
            if (TcpOfflineFileClient != null)
                TcpOfflineFileClient.CancelTransmit();//取消离线文件传输
        }

        /// <summary>
        /// 请求NAT穿越
        /// </summary>
        /// <param name="hostid">对端主机ID</param>
        public void RequestNATIntroduction(long hostid)
        {
            if (isSend)
            { 
                P2PFileTransmit.Start();
                System.Threading.Thread.Sleep(1);
            }
            P2PFileTransmit.RequestNATIntroduction(hostid);
        }
        #endregion

    }
}
